import {Server} from "http";
import socketIO = require('socket.io');
import * as io from "socket.io-client"
import {Log} from "../Log";
import {RpcClass} from "./RpcClass";
import {InnerRpc} from "./InnerRpc";
import {IHttpServer, IRpc} from "../IHttpServer";


/**
 * _rpc 请求格式： [入参...,类名，函数名，唯一id]
 * _ret 响应格式： [是否成功，唯一id,返回值或异常]
 */
export class RpcServer {


    io: SocketIO.Server | null = null;

    static initAllFunc(rpcClass: { new(): any }) {
        let funcs = Object.getOwnPropertyNames(rpcClass)
        for (let f of funcs) {
            if (f === "length" || f === "name" || f === "prototype")
                continue;
            let func = rpcClass[f];


            if (func instanceof Function) {
                func();
            }

        }

    }

    static removeTimeOut(time: number) {
        for (var m of RpcClass.rpcMap) {
            var k = m[0];
            var v = m[1];
            if (v.startTime.getDate() < time) {
                RpcClass.rpcMap.delete(k);
                v.reject(Error("rpc超时"));
            }
            else {
                break;
            }

        }

    }

    /**
     * 启动prc服务
     * @param server 端口号
     * @param rpcClass rpc业务类名
     * @returns {RpcServer}
     */
    static serverStart(server: Server | number, rpcClass?: { new(): any }): RpcServer {
        let rpc = new RpcServer();

        rpc.io = socketIO(server);

        console.log("rpc listening on port " + server);
        rpc.io.on('connection', function (socket: SocketIO.Socket) {
            Log.write('new rpc connection :' + socket.conn.remoteAddress);

            socket.on('_rpc', function (from: any[], msg: any) {
                if (!from.length || from.length < 3) {
                    Log.write(socket.client.conn.remoteAddress + "非法链接：" + JSON.stringify(from))
                    socket.disconnect(true);
                    return;
                }

                let id = from.pop() as string;
                let func = from.pop() as string;
                let className = from.pop() as string;
                let cals = RpcClass.instMap[className];
                if (!cals) {
                    Log.write(socket.client.conn.remoteAddress + "非法类名：" + JSON.stringify(from))
                    socket.disconnect(true);
                    return;
                }
                try {
                    let ret = cals[func].apply(cals, from);
                    if (ret instanceof Promise) {
                        ret.then(res => {
                            if (res === void 0)
                                socket.emit("_ret", [1, id]);
                            else
                                socket.emit("_ret", [1, id, res]);
                        }).catch(err => {
                            Log.write("rpc异常：", err)
                            socket.emit("_ret", [0, id, err + ""]);
                        })
                    }
                } catch (e) {
                    Log.write("rpc异常：", e)
                    socket.emit("_ret", [0, id, e.toString()]);
                }

            });

            socket.on('disconnect', function () {
                Log.write('rpc disconnect:' + socket.conn.remoteAddress);
            });
        });

        if (rpcClass)
            RpcServer.initAllFunc(rpcClass);

        RpcServer.inner(null);

        //5秒后探测自己的主机名
        // if (initHostName) {
        //     setTimeout(() => {
        //         RpcServer.initHostName(servers);
        //     }, 5 * 1000);
        // }

        // if (servers.length > 1) {
        //     InnerRpc.servers = servers;
        // }
        return rpc;
    }

    static inner(iHttpServer: IRpc | null) {
        return RpcServer.addClass(InnerRpc, iHttpServer);
    }

    static getHostName(server: IRpc) {
        return "http://" + server.host + ":" + server.portRpc;
    }

    /**
     * 探测自己的主机名
     * @param servers 服务器列表
     */
    static initHostName(servers: IRpc[]) {
        for (let s of servers) {
            RpcServer.inner(s).getPid().then(pid => {
                if (pid == process.pid) {
                    let host = RpcServer.getHostName(s);
                    RpcClass.hostName[host] = true;
                    let sock = RpcClass.sockets[host];
                    if (sock) {
                        sock.close();
                        delete RpcClass.sockets[host];
                    }
                }
            });
        }


    }


    static connect() {
        var socket = io.connect("http://192.168.137.2:3000", {transports: ['websocket']})
        socket.emit('_rpc', ["1234", "aaaa", "333"]);


        setInterval(() => {
            socket.emit('_rpc', ["aaaaa", "bbbbb", "ccccc"]);
        }, 3000)
        socket.on("error", err => {
            console.log('error' + err);
        })

        socket.on("connect_error", err => {
            console.log('connect_error' + err);
        })

        socket.on("connect_timeout", err => {
            console.log('connect_timeout' + err);
        })

        socket.on("disconnect", err => {
            console.log('disconnect' + err);
        })
    }


    /**
     * 添加rpc业务逻辑类
     * @param rpcClass
     * @param iHttpServer
     * @returns {T}
     */
    static addClass<T>(rpcClass: { new(): T }, iHttpServer: IRpc | null): T {
        let rpcInst = (rpcClass as any).__rpcClass_ as RpcClass;
        if (!rpcInst) {
            rpcInst = new RpcClass(rpcClass);
            (rpcClass as any).__rpcClass_ = rpcInst;
        }
        if (iHttpServer)
            rpcInst.httpServer = RpcServer.getHostName(iHttpServer)

        return rpcInst.clasRpc as T;
    }
}
